package com.livestocksolutions.ui;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.AbstractDocument;

import com.livestocksolutions.Business;
import com.livestocksolutions.Chemical;
import com.livestocksolutions.ChemicalHistory;
import com.livestocksolutions.LivestockSolutions;
import com.livestocksolutions.Observation;
import com.livestocksolutions.Owner;
import com.livestocksolutions.Paddock;
import com.livestocksolutions.util.Comparators;
import com.livestocksolutions.util.DecimalDocumentFilter;
import com.livestocksolutions.util.JDatePickerDate;
import com.livestocksolutions.util.Table;
import com.livestocksolutions.util.UsableItemList;

/**
 * Display details relating to any Paddock, or a particular Paddock.
 * @author Ken DeVries
 * @author Adam Parr
 * 
 * @.modified 19 March 2013
 */
public class PaddockPanel extends JPanel implements TabbedInterface {
	private static final long serialVersionUID = 1L;
	
	/**
	 * The initial view for this tab.
	 * Shows all Paddock that are in the system.
	 */
	public static final int PADDOCK_LIST = 0;
	/**
	 * To create a new Paddock.
	 */
	public static final int VIEW_NEW_PADDOCK=1;
	/**
	 * To view a Paddock details.
	 */
	public static final int VIEW=2;
	/**
	 * To view a Paddock details, showing all Observations.
	 */
	public static final int VIEW_OBSERVATION=3;
	/**
	 * Shows Details of the selected Paddock and also any Chemicals for that Padock.
	 */
	public static final int VIEW_CHEMICALS = 4;

	/**
	 * Sort the paddock list by name.
	 */
	protected static final int LIST_ORDER_NAME = 0;
	/**
	 * Sort the paddock list by area size.
	 */
	protected static final int LIST_ORDER_AREA = 1;
	/**
	 * Sort the paddock list by safe grazing status.
	 */
	protected static final int LIST_ORDER_SAFEGRAZING = 2;
	
	/**
	 * Sort the observation list by Creation Date.
	 */
	protected static final int LIST_ORDER_DATE = 1;
	/**
	 * Sort the observation list by using the Priority.
	 */
	protected static final int LIST_ORDER_PRIORITY 	= 0;
	
	/**
	 * Sort the UsableItemHistory list by using quantity given.
	 */
	protected static final int LIST_ORDER_QTY		= 2;
	
	/**
	 * Order the Paddock list.
	 * @see #LIST_ORDER_NAME
	 * @see #LIST_ORDER_AREA
	 * @see #LIST_ORDER_SAFEGRAZING
	 */
	protected int orderPaddockListBy = LIST_ORDER_NAME;
	
	/**
	 * The items Observation list order method.
	 * @see #LIST_ORDER_DATE
	 * @see #LIST_ORDER_PRIORITY
	 */
	protected int orderObservationListBy = LIST_ORDER_DATE;
	
	/**
	 * Order the UsableItem History list.
	 * @see #LIST_ORDER_NAME
	 * @see #LIST_ORDER_DATE
	 * @see #LIST_ORDER_QTY
	 */
	protected int orderChemicalItemListBy = LIST_ORDER_NAME;
	/**
	 * The sort direction. Ascending : 1, Descending -1;
	 */
	protected int orderPaddockHighToLow = 1, orderObservationHighToLow = 1, orderChemicalItemHighToLow = 1;
	
	/**
	 * Determine if the editable details of a Paddock is editable.
	 */
	protected boolean edit = false;
	
	/**
	 * The current view.
	 * 
	 * @see #PADDOCK_LIST
	 * @see #VIEW_NEW_PADDOCK
	 * @see #VIEW
	 * @see #VIEW_OBSERVATION
	 * @see #VIEW_CHEMICALS
	 */
	private int viewing = -1;
	
	/**
	 * The ID of the Paddock we are Viewing.
	 */
	protected long locationViewID = 0;

	protected final JPanel panel = new JPanel();
	
	/**
	 * The Panel where the innerlist for a particular item will rest.
	 */
	protected JTabbedPane jisp = new JTabbedPane();
	protected final JPanel observationsListPanel = new JPanel();
	protected final JPanel chemicalsListPanel = new JPanel();
	
	protected JComboBox typeCB = new JComboBox();
	protected JTextField areaSpinner = new JTextField();
	protected JTextField txtName = new JTextField();
	protected JTextArea txtDescription = new JTextArea();
	
	/**
	 * Constructor
	 */
	public PaddockPanel(){
		JScrollPane jsp = new JScrollPane();
		setLayout(new BorderLayout(0, 0));
		jsp.setViewportView(panel);
		jsp.setViewportBorder(BorderFactory.createEmptyBorder());

		add(jsp);
		panel.setLayout(new BorderLayout(10, 10));

		AdjustmentListener al = new AdjustmentListener(){
			@Override
			public void adjustmentValueChanged(AdjustmentEvent evt) {
				panel.repaint();
			}
		};
		jsp.getHorizontalScrollBar().addAdjustmentListener(al);
		jsp.getVerticalScrollBar().addAdjustmentListener(al);

		((AbstractDocument)areaSpinner.getDocument()).setDocumentFilter(new DecimalDocumentFilter(0d,Double.POSITIVE_INFINITY));
		areaSpinner.setColumns(5);
		typeCB = new JComboBox(new String[]{Paddock.getUnitString(Paddock.HA),Paddock.getUnitString(Paddock.ACRE)});
	}
	
	@Override 
	public void displayPanel(){
		int panel = viewing;
		if(viewing==PADDOCK_LIST) {
			viewing=-1;
			panel = PADDOCK_LIST;
		}
		displayPanel(panel);
	}
	
	/**
	 * @see #PADDOCK_LIST
	 * @see #VIEW_NEW_PADDOCK
	 * @see #VIEW
	 * @see #VIEW_OBSERVATION
	 * @see #VIEW_CHEMICALS
	 */
	@Override
	public void displayPanel(int panel){
		switch (panel){
			case PADDOCK_LIST:
				if(viewing!=PADDOCK_LIST){
					createHomePanel();
				}
				break;
			case VIEW_NEW_PADDOCK:
				if(viewing!=VIEW_NEW_PADDOCK){
					createPaddockPanel(-1);
				}
				break;
			case VIEW:
			case VIEW_OBSERVATION:
			case VIEW_CHEMICALS:
				createPaddockPanel(locationViewID);
				break;
			default :
				createHomePanel();
		}
	}
	
	/**
	 * Create the list of Paddocks to chose from.
	 */
	private void createHomePanel(){
		viewing = PADDOCK_LIST;
		
		locationViewID=0;
		panel.setLayout(new BorderLayout(0, 0));
		
		final int NAME	 		= 0;
		final int AREA			= 1;
		final int DESC			= 2;
		final int SAFEGRAZING	= 3;
		
		final Table paddockPanel = new Table("Paddocks",false,
			"Name","Area","Description","Safe for Grazing");
		paddockPanel.setEmptyMessage("There are no Paddocks to show.");
		
		new Thread(){
			@Override
			public void run(){
				while(!LivestockSolutions.isReady()){
					try {
						sleep(500);
					} catch (InterruptedException e) {}
					if(LivestockSolutions.close){
						return;
					}
				}
				
				paddockPanel.setHeaderOrderedBy(orderPaddockListBy==LIST_ORDER_NAME?NAME:orderPaddockListBy==LIST_ORDER_AREA?AREA:orderPaddockListBy==LIST_ORDER_SAFEGRAZING?SAFEGRAZING:NAME, orderPaddockHighToLow==1);
				paddockPanel.setHeaderClickable(DESC, false);
				paddockPanel.addHeaderMouseListener(NAME, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderPaddockHighToLow = orderPaddockHighToLow*(orderPaddockListBy==LIST_ORDER_NAME?-1:1);
						orderPaddockListBy = LIST_ORDER_NAME;
						createHomePanel();
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				paddockPanel.addHeaderMouseListener(AREA, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderPaddockHighToLow = orderPaddockHighToLow*(orderPaddockListBy==LIST_ORDER_AREA?-1:1);
						orderPaddockListBy = LIST_ORDER_AREA;
						createHomePanel();
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				paddockPanel.addHeaderMouseListener(SAFEGRAZING, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderPaddockHighToLow = orderPaddockHighToLow*(orderPaddockListBy==LIST_ORDER_SAFEGRAZING?-1:1);
						orderPaddockListBy = LIST_ORDER_SAFEGRAZING;
						createHomePanel();
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				Paddock[] pList = LivestockSolutions.getOnlyPaddocks();
				Arrays.sort(pList, orderPaddockListBy==LIST_ORDER_NAME?Comparators.paddockComparatorName:orderPaddockListBy==LIST_ORDER_AREA?Comparators.paddockComparatorArea:Comparators.paddockComparatorSafeGrazing);
				
				for(int x=0; x<pList.length; x++){
					String subComment = pList[x].getDescription();
					if(pList[x].getDescription().length()>97){
						subComment = pList[x].getDescription().substring(0,97)+"...";
					}
					paddockPanel.addRow(
						new JLabel(pList[x].getName()),
						new JLabel(pList[x].getArea() + " "+ Paddock.getUnitString(pList[x].getUnits())),
						new JLabel(subComment),
						new JLabel(pList[x].getSafeGrazingDate()!=null&&pList[x].getSafeGrazingDate().after(new Date())?JDatePickerDate.format(pList[x].getSafeGrazingDate()):"Safe"));
					
					final long id = pList[x].getID();
					paddockPanel.addMouseListener(new MouseListener(){
						@Override
						public void mouseClicked(MouseEvent e) {
							if(createPaddockPanel(id)){
								// Show Paddock not found message?
							}
						}
						@Override public void mousePressed(MouseEvent e) {}
						@Override public void mouseReleased(MouseEvent e) {}
						@Override public void mouseEntered(MouseEvent e) {}
						@Override public void mouseExited(MouseEvent e) {}
					});
				}
				validate();
			}
		}.start();
		
		panel.removeAll();
		JPanel container = new JPanel();
		container.setLayout(new BorderLayout(10,10));
		JPanel buttonPanel = new JPanel();
		((FlowLayout)buttonPanel.getLayout()).setAlignment(FlowLayout.RIGHT);
		
		JButton btnNewCattle = new JButton("New Paddock");
		btnNewCattle.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				createPaddockPanel(-1L);
			}
		});
		buttonPanel.add(btnNewCattle);
		container.add(buttonPanel,BorderLayout.NORTH);
		container.add(paddockPanel,BorderLayout.CENTER);
		panel.add(container,BorderLayout.NORTH);
		panel.repaint();
	}
	
	/**
	 * Show the details for this Paddock with the given ID
	 * @param locationID The internal Id that identifies this Paddock
	 * @return <tt>true</tt> If a Paddock with the Id exists and was shown, <tt>false</tt> otherwise.
	 */
	public boolean createPaddockPanel(final long locationID){
		if(locationViewID != locationID){
			viewing=VIEW;
			locationViewID = locationID;
			if(jisp.getParent()!=null)
				jisp.getParent().remove(jisp);
			jisp = new JTabbedPane();
			
			edit=false;
			txtName.setText("-1");
		}

		panel.setLayout(new BorderLayout(10, 10));
		panel.removeAll();
		final Paddock p = (Paddock)LivestockSolutions.getLocationByID(locationID);
		JPanel container = new JPanel();
		container.setLayout(new BorderLayout(10, 10));
		JPanel flowPanel = new JPanel();
		JPanel panel_1 = new JPanel();
		panel_1.setLayout(new BorderLayout(0, 10));
		flowPanel.add(panel_1);
		container.add(flowPanel,BorderLayout.CENTER);
		panel.add(container,BorderLayout.NORTH);
		
		/**
		 * The Paddock that is being shown.
		 */
		JButton btnHome = new JButton("Paddock List");
		btnHome.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				edit=false;
				txtName.setText("-1");
				viewing=-1;

				displayPanel(PADDOCK_LIST);
			}
		});
		
		JButton btnCancel = new JButton(locationViewID!=-1?"Cancel":"Clear");
		btnCancel.setVisible(edit);
		btnCancel.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				edit=false;
				txtName.setText("-1");
				displayPanel(viewing);
			}
		});
		JPanel buttonMenuLeft = new JPanel();
		JPanel buttonMenuRight = new JPanel();
		((FlowLayout)buttonMenuLeft.getLayout()).setAlignment(FlowLayout.LEFT);
		((FlowLayout)buttonMenuRight.getLayout()).setAlignment(FlowLayout.RIGHT);
		buttonMenuLeft.add(btnHome);
		
		final JButton btnCreateSave = new JButton(locationViewID==-1?"Create":edit?"Save":"Edit");
		btnCreateSave.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				if(edit){
					Paddock p = (Paddock)LivestockSolutions.getLocationByID(locationViewID);
					if(p==null){
						p = new Paddock();
					}
					p.setName(txtName.getText());
					p.setArea(Double.parseDouble(areaSpinner.getText()));
					p.setUnits(typeCB.getSelectedIndex());
					p.setDescription(txtDescription.getText());
					
					if(LivestockSolutions.addLocation(p)){
						PaddockPanel.this.locationViewID=p.getID();
						txtName.setText("-1");
						edit=!edit;
					}else{
						JOptionPane.showMessageDialog(MainFrame.getInstance(),"Failed to save changes.","Failed to Save", JOptionPane.OK_OPTION);
					}
				}else{
					txtName.setText("-1");
					edit=!edit;
				}
				displayPanel(viewing);
			}
		});		
		
		JPanel buttonMenu = new JPanel();
		buttonMenu.setLayout(new BorderLayout());
		buttonMenuRight.add(btnCreateSave);
		buttonMenuRight.add(btnCancel);
		buttonMenu.add(buttonMenuLeft,BorderLayout.WEST);
		buttonMenu.add(buttonMenuRight,BorderLayout.EAST);
		container.add(buttonMenu,BorderLayout.NORTH);
		
		if(p!=null || locationID==-1){
			String name="";
			String desc = "";
			String units = Paddock.getUnitString(Paddock.ACRE);
			String stu = "";
			double area = 0.0;
			boolean refresh=false;
			if(!txtName.getText().equals("-1")){
				refresh=true;
			}
			
			if(p!=null){
				name = p.getName();
				desc = p.getDescription();
				area = p.getArea();
				units = Paddock.getUnitString(p.getUnits());
				Date sgd = p.getSafeGrazingDate();
				sgd = sgd==null?null:sgd.after(new Date())?sgd:null;
				stu = sgd==null?"":"Safe to use after: "+ JDatePickerDate.format(sgd);
			}else{
				if(locationID==-1){
					edit=true;
				}
			}

			if(!refresh){
				jisp.setOpaque(false);
				jisp.setBorder(new EmptyBorder(0,0,0,0));
				jisp.addTab("Observations",MainFrame.scale(MainFrame.getImageIcon(MainFrame.OBSERVATION_LIST),MainFrame.ICON_WIDTH,MainFrame.ICON_HEIGHT), observationsListPanel);
				jisp.addTab("Applied Chemicals",MainFrame.scale(MainFrame.getImageIcon(MainFrame.CHEMICAL_LIST),MainFrame.ICON_WIDTH,MainFrame.ICON_HEIGHT), chemicalsListPanel);
				jisp.addMouseListener(new MouseListener(){
					@Override public void mouseClicked(MouseEvent e) {}
					@Override public void mousePressed(MouseEvent e) {
						new Thread(){@Override
						public void run(){
							if(jisp.getSelectedComponent()==observationsListPanel)
								createObservationsPanel(locationID);
							else if(jisp.getSelectedComponent()==chemicalsListPanel)
								createChemicalPanel(locationID);
						}}.start();
					}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				jisp.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
				jisp.setAutoscrolls(true);
				
				jisp.setBorder(new EmptyBorder(0,0,0,0));
			}			
			panel_1.setLayout(new BorderLayout(5, 0));
			
			JPanel panel_2 = new JPanel();
			panel_1.add(panel_2, BorderLayout.NORTH);
			panel_2.setLayout(new BorderLayout(5, 0));
			
			JPanel namePanel = new JPanel();
			panel_2.add(namePanel, BorderLayout.WEST);
			namePanel.setLayout(new BoxLayout(namePanel, BoxLayout.PAGE_AXIS));
			
			JPanel paddockNamePanel = new JPanel();
			namePanel.add(paddockNamePanel);
			paddockNamePanel.setLayout(new BorderLayout(0, 0));
	
			paddockNamePanel.add(new JLabel("Name:"));
			
			JPanel paddockAreaPanel = new JPanel();
			namePanel.add(paddockAreaPanel);
			paddockAreaPanel.setLayout(new BorderLayout(0, 0));
	
			paddockAreaPanel.add(new JLabel("Area:"));
			
			JPanel valuePanel = new JPanel();
			panel_2.add(valuePanel, BorderLayout.CENTER);
			valuePanel.setLayout(new BoxLayout(valuePanel, BoxLayout.PAGE_AXIS));
			
			/**
			 * A check to determine if the item in its current state is valid to be saved.
			 * @see #doCheck()
			 */
			final DocumentListener dl = new DocumentListener() {
				public void changedUpdate(DocumentEvent e) {
					doCheck();
				}
				public void removeUpdate(DocumentEvent e) {
					doCheck();
				}
				public void insertUpdate(DocumentEvent e) {
					doCheck();
				}
				
				/**
				 * Checks to see if it is OK to save the item as it currently is.<br>
				 * Disables the save button if it is not OK, enables it if it is.
				 */
				private void doCheck(){
					boolean valid=false;
					if(!txtName.getText().trim().equals("")&&edit){
						valid=true;
						
					}

					btnCreateSave.setEnabled(edit?valid:true);
				}
			};
			
			txtName.getDocument().addDocumentListener(dl);
			txtName.setText(refresh?txtName.getText():name);
			txtName.setEditable(edit);
			valuePanel.add(txtName);
			txtName.setColumns(10);
			
			JPanel areaPanel = new JPanel();
			valuePanel.add(areaPanel);
			areaPanel.setLayout(new BorderLayout(5, 0));
			
			areaSpinner.getDocument().addDocumentListener(dl);
			areaSpinner.setText(refresh?areaSpinner.getText():Double.toString(area));
			areaSpinner.setEnabled(edit);
			areaPanel.add(areaSpinner);
	
			typeCB.setSelectedItem(refresh?typeCB.getSelectedItem():units);
			typeCB.setEnabled(edit);
			areaPanel.add(typeCB, BorderLayout.EAST);
			
			JPanel listPanel = new JPanel();
			listPanel.setLayout(new BorderLayout(0, 0));
			JPanel paddockDescPanel = new JPanel();
			paddockDescPanel.setBorder(new EmptyBorder(0, 5, 5, 5));
			listPanel.add(paddockDescPanel, BorderLayout.NORTH);
			listPanel.add(jisp,BorderLayout.CENTER);
			panel.add(listPanel, BorderLayout.CENTER);
			paddockDescPanel.setLayout(new BorderLayout(0, 5));
	
			paddockDescPanel.add(new JLabel("Description:"), BorderLayout.WEST);
			
			txtDescription.setText(refresh?txtDescription.getText():desc);
			txtDescription.setEditable(edit);
			txtDescription.setRows(3);
			paddockDescPanel.add(txtDescription, BorderLayout.SOUTH);
			
			JPanel safeToUsePanel = new JPanel();
			JLabel lblSafeToUse = new JLabel(stu);
			safeToUsePanel.add(lblSafeToUse);
			panel_1.add(safeToUsePanel, BorderLayout.SOUTH);

			if(viewing == VIEW_CHEMICALS){
				jisp.setSelectedComponent(chemicalsListPanel);
				createChemicalPanel(locationID);
			}else if(viewing == VIEW_OBSERVATION || viewing == VIEW){
				jisp.setSelectedComponent(observationsListPanel);
				createObservationsPanel(locationID);
			}
		}else{
			panel.removeAll();
			panel.setLayout(new BorderLayout(10, 10));
			JPanel flow =new JPanel();
			JLabel label = new JLabel("No Such Paddock can be found with the given internal id: "+locationID);
			flow.add(label);
			panel.add(flow,BorderLayout.NORTH);
			return false;
		}
		validate();
		
		return true;
	}
	
	/**
	 * Create a list of observations that belong to this Paddock.
	 * @param locationID The long ID value that represents the Paddock to show the Observations for.
	 */
	private void createObservationsPanel(final long locationID){
		viewing = VIEW_OBSERVATION;
		
		observationsListPanel.setLayout(new BorderLayout());
		
		final int DATE 		= 0;
		final int DESCRIPTION 	= 1;
		final int PRIORITY 	= 2;
		
		final Table observationPanel = new Table("Observations",false,
			"Date","Description","Priority");
		observationPanel.setEmptyMessage("There are no observations to show.");
		
		final Paddock l = (Paddock)LivestockSolutions.getLocationByID(locationID);
		new Thread(){
			@Override
			public void run(){
				observationPanel.setHeaderClickable(DESCRIPTION, false);
				observationPanel.setHeaderOrderedBy(orderObservationListBy==LIST_ORDER_DATE?DATE:orderObservationListBy==LIST_ORDER_PRIORITY?PRIORITY:DATE, orderObservationHighToLow==1);
				observationPanel.addHeaderMouseListener(DATE, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderObservationHighToLow = orderObservationHighToLow*(orderObservationListBy==LIST_ORDER_DATE?-1:1);
						orderObservationListBy = LIST_ORDER_DATE;
						createObservationsPanel(locationID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				observationPanel.addHeaderMouseListener(PRIORITY, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderObservationHighToLow = orderObservationHighToLow*(orderObservationListBy==LIST_ORDER_PRIORITY?-1:1);
						orderObservationListBy = LIST_ORDER_PRIORITY;
						createObservationsPanel(locationID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				Observation[] oList = l!=null?l.getObservations():new Observation[]{};
				
				Arrays.sort(oList, 
					orderObservationListBy==LIST_ORDER_DATE?
							orderObservationHighToLow==1?Comparators.observationComparatorDate:Collections.reverseOrder(Comparators.observationComparatorDate)
					:orderObservationHighToLow==1?Comparators.observationComparatorPriority:Collections.reverseOrder(Comparators.observationComparatorPriority));

				for(int x=0; x<oList.length; x++){
					observationPanel.addRow(
						new JLabel(JDatePickerDate.format(oList[x].getDate())),
						new JLabel(oList[x].getComment()),
						new JLabel(Observation.getPriorityString(oList[x].getPriority())));
					
					final Observation o = oList[x];
					
					observationPanel.addMouseListener(new MouseListener(){
						@Override
						public void mouseClicked(MouseEvent e) {
							new ObservationFrame(l,o,"Paddock: "+l.getName()).addWindowListener(new WindowListener(){
								@Override public void windowOpened(WindowEvent e) {}
								@Override
								public void windowClosing(WindowEvent e) {
									// Refresh Page
									if(viewing==VIEW_OBSERVATION && locationViewID==locationID){
										createObservationsPanel(locationID);
									}
								}
								@Override public void windowClosed(WindowEvent e) {}
								@Override public void windowIconified(WindowEvent e) {}
								@Override public void windowDeiconified(WindowEvent e) {}
								@Override public void windowActivated(WindowEvent e) {}
								@Override public void windowDeactivated(WindowEvent e) {}
							});
						}
						@Override public void mousePressed(MouseEvent e) { }
						@Override public void mouseReleased(MouseEvent e) {}
						@Override public void mouseEntered(MouseEvent e) {}
						@Override public void mouseExited(MouseEvent e) {}
					});
				}
				validate();
			}
		}.start();
		
		final JButton btnAddObservation = new JButton("Add Observation");
		btnAddObservation.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				new ObservationFrame(l,null,"Paddock: "+l.getName()).addWindowListener(new WindowListener(){
					@Override
					public void windowClosing(WindowEvent e) {
						// Refresh Page
						if(viewing==VIEW_OBSERVATION && PaddockPanel.this.locationViewID==locationViewID){
							createObservationsPanel(locationViewID);
						}
					}
					@Override public void windowOpened(WindowEvent e) {}
					@Override public void windowClosed(WindowEvent e) {}
					@Override public void windowIconified(WindowEvent e) {}
					@Override public void windowDeiconified(WindowEvent e) {}
					@Override public void windowActivated(WindowEvent e) {}
					@Override public void windowDeactivated(WindowEvent e) {}
				});
				observationPanel.addRow(null,new JLabel("<New Observation>"),null);
				btnAddObservation.setEnabled(false);
				observationPanel.validate();
				panel.validate();
			}
		});

		observationsListPanel.removeAll();
		JPanel container = new JPanel();
		container.setLayout(new BorderLayout(10,10));
		JPanel buttonPanel = new JPanel();
		((FlowLayout)buttonPanel.getLayout()).setAlignment(FlowLayout.RIGHT);
		buttonPanel.add(btnAddObservation);
		container.add(buttonPanel,BorderLayout.NORTH);
		container.add(observationPanel,BorderLayout.CENTER);
		observationsListPanel.add(container, BorderLayout.NORTH);
		panel.validate();
			
		jisp.setSelectedComponent(observationsListPanel);
	}
	
	/**
	 * Create a list of Chemical Item Usage that belong to this Paddock.
	 * @param locationID The long ID value that represents the Paddock to show the list for.
	 */
	private void createChemicalPanel(final long locationID){
		viewing = VIEW_CHEMICALS;
		
		chemicalsListPanel.setLayout(new BorderLayout());
		final int ADD	 	= 0;
		final int ITEM	 	= 1;
		final int DATE 		= 2;
		final int QTY 		= 3;
		
		final Paddock p = (Paddock)LivestockSolutions.getLocationByID(locationID);
		
		final Table chemicalPanel = new Table("Chemical",false,
			"","Chemical Name","Date Used","Quantity","Expiration Date","Price","Manufacturer","Manufacture Date","Batch Number");
		chemicalPanel.setEmptyMessage("No chemicals have been used on this paddock before.");
		chemicalPanel.setColumnVisible(ADD, edit);
		new Thread(){
			@Override
			public void run(){
				chemicalPanel.setHeaderOrderedBy(
					orderChemicalItemListBy==LIST_ORDER_NAME?ITEM
					:orderChemicalItemListBy==LIST_ORDER_DATE?DATE
					:orderChemicalItemListBy==LIST_ORDER_QTY?QTY
					:DATE, orderChemicalItemHighToLow==1);
 
				chemicalPanel.addHeaderMouseListener(ITEM, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderChemicalItemHighToLow = orderChemicalItemHighToLow*(orderChemicalItemListBy==LIST_ORDER_NAME?-1:1);
						orderChemicalItemListBy = LIST_ORDER_NAME;
						createChemicalPanel(locationID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				chemicalPanel.addHeaderMouseListener(DATE, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderChemicalItemHighToLow = orderChemicalItemHighToLow*(orderChemicalItemListBy==LIST_ORDER_DATE?-1:1);
						orderChemicalItemListBy = LIST_ORDER_DATE;
						createChemicalPanel(locationID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				chemicalPanel.addHeaderMouseListener(QTY, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderChemicalItemHighToLow = orderChemicalItemHighToLow*(orderChemicalItemListBy==LIST_ORDER_QTY?-1:1);
						orderChemicalItemListBy = LIST_ORDER_QTY;
						createChemicalPanel(locationID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});

				ChemicalHistory[] cList = p!=null?p.getChemicalsUsed():new ChemicalHistory[]{};
				Arrays.sort(cList,
					orderChemicalItemListBy==LIST_ORDER_NAME?
							orderChemicalItemHighToLow==1?Comparators.usableItemHistoryComparatorName:Collections.reverseOrder(Comparators.usableItemHistoryComparatorName)
					:orderChemicalItemListBy==LIST_ORDER_DATE?
							orderChemicalItemHighToLow==1?Comparators.usableItemHistoryComparatorDate:Collections.reverseOrder(Comparators.usableItemHistoryComparatorDate)
					:orderChemicalItemListBy==LIST_ORDER_QTY?
							orderChemicalItemHighToLow==1?Comparators.usableItemHistoryComparatorQty:Collections.reverseOrder(Comparators.usableItemHistoryComparatorQty)
					:orderChemicalItemListBy==1?Comparators.usableItemHistoryComparatorPurchaseDate:Collections.reverseOrder(Comparators.usableItemHistoryComparatorPurchaseDate));

				for(int x=0; x<cList.length; x++){									
					chemicalPanel.addRow(
						null,
						new JLabel(cList[x].getItem().getName()),
						new JLabel(cList[x].getDate()!=null?JDatePickerDate.format(cList[x].getDate()):"Unknown"),
						new JLabel(cList[x].getQuantity()+" "+cList[x].getMeasurement()));
					
					final ChemicalHistory ch = cList[x];
					chemicalPanel.addMouseListener(new MouseListener(){
						@Override
						public void mouseClicked(MouseEvent e) {
							new PaddockUsedChemical(p,ch).addWindowListener(new WindowListener(){
								@Override public void windowOpened(WindowEvent e) {}
								@Override
								public void windowClosing(WindowEvent e) {
									// Refresh Page
									if(viewing==VIEW_CHEMICALS && locationViewID==locationID){
										createChemicalPanel(locationID);
									}
								}
								@Override public void windowClosed(WindowEvent e) {}
								@Override public void windowIconified(WindowEvent e) {}
								@Override public void windowDeiconified(WindowEvent e) {}
								@Override public void windowActivated(WindowEvent e) {}
								@Override public void windowDeactivated(WindowEvent e) {}
							});
						}
						@Override public void mousePressed(MouseEvent e) {}
						@Override public void mouseReleased(MouseEvent e) {}
						@Override public void mouseEntered(MouseEvent e) {}
						@Override public void mouseExited(MouseEvent e) {}
					});
				}
				validate();
			}
		}.start();
		
		final JButton btnAddChemical = new JButton("Add Chemical");

		btnAddChemical.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				PaddockUsedChemical pc = new PaddockUsedChemical(p,null);
				chemicalPanel.addRow(null,new JLabel("<New Applied Chemical>"),null);
				btnAddChemical.setEnabled(false);
				chemicalPanel.validate();
				panel.validate();
				pc.addWindowListener(new WindowListener(){
					@Override
					public void windowClosing(WindowEvent e) {
						// Refresh Page
						if(viewing==VIEW_CHEMICALS && PaddockPanel.this.locationViewID==locationViewID){
							createChemicalPanel(locationViewID);
						}
					}
					@Override public void windowOpened(WindowEvent e) {}
					@Override public void windowClosed(WindowEvent e) {}
					@Override public void windowIconified(WindowEvent e) {}
					@Override public void windowDeiconified(WindowEvent e) {}
					@Override public void windowActivated(WindowEvent e) {}
					@Override public void windowDeactivated(WindowEvent e) {}
				});
			}
		});

		chemicalsListPanel.removeAll();
		JPanel container = new JPanel();
		container.setLayout(new BorderLayout(10,10));
		JPanel buttonPanel = new JPanel();
		((FlowLayout)buttonPanel.getLayout()).setAlignment(FlowLayout.RIGHT);
		buttonPanel.add(btnAddChemical);
		container.add(buttonPanel,BorderLayout.NORTH);
		container.add(chemicalPanel,BorderLayout.CENTER);
		chemicalsListPanel.add(container, BorderLayout.NORTH);
		panel.validate();
		
		jisp.setSelectedComponent(chemicalsListPanel);
	}

	@Override
	public long getID() {
		return locationViewID;
	}
	
	/**
	 * Create a window where a chemical that has been used on the current paddock can be viewed and modified.
	 * @author Adam Parr
	 */
	private static class PaddockUsedChemical extends UsedItemFrame<Paddock,ChemicalHistory,Chemical>{
		private static final long serialVersionUID = 1L;
		protected JDatePickerDate expiration;
		protected JDatePickerDate manuDate;
		protected JTextField batchNo;
		
		/**
		 * Constructor.
		 * @param parent The Paddock in which the usedChemicalHistory has been applied on.
		 * @param usedChemicalHistory the usage history of a particular Chemical, or <tt>null</tt> in the
		 * 			case of a new Chemical usage being used on the Paddock provided in parent.
		 */
		protected PaddockUsedChemical(Paddock parent,ChemicalHistory usedChemicalHistory) {
			super(parent, usedChemicalHistory);
			setTitle((usedChemicalHistory==null?"Add a new Chemical":"Modify "+usedChemicalHistory.getItem().getName())+" for use on "+parent.getName());
		}

		@Override
		protected boolean doCheck(boolean isValid) {
			// Additional values for the UsedChemical are optional.
			return isValid;
		}

		@SuppressWarnings("unchecked")
		@Override
		protected UsableItemList<Chemical>[] getList() {
			Chemical[] mArrayList = LivestockSolutions.getOnlyChemicals();
			int length=mArrayList.length;
			UsableItemList<Chemical>[] chlist = new UsableItemList[length];
			for(int x=0;x<length;x++){
				chlist[x]=new UsableItemList<Chemical>(mArrayList[x]);
			}
			return chlist;
		}
		
		@Override
		protected void createSecondaryValues(final Paddock parent, final ChemicalHistory usedItemHistory){
			super.createSecondaryValues(parent, usedItemHistory);
			int length = cost.getParent().getComponentCount();
			JPanel panel = (JPanel)cost.getParent();
			expiration = JDatePickerDate.createJDatePicker();
			expiration.setTextEditable(true);
			batchNo = new JTextField();
			manuDate = JDatePickerDate.createJDatePicker();
			manuDate.setTextEditable(true);
			for(int x=0; x<length; x++){
				Component c = panel.getComponent(x);	
				if(c.equals(cost)){
					panel.add(expiration,x+1);
					panel.add(new JLabel("Expiration Date:"),x+1);
					x+=2;
				}
			}
			panel.add(new JLabel("Manufacture Date:"));
			panel.add(manuDate);
			panel.add(new JLabel("Batch Number:"));
			panel.add(batchNo);
			batchNo.setColumns(10);
			pack();
		}
		
		@Override
		protected void setTextInOptionalFields(ChemicalHistory usedItemHistory){
			super.setTextInOptionalFields(usedItemHistory);
			if(usedItemHistory!=null){
				expiration.setDate(usedItemHistory.getExpiryDate());
				manuDate.setDate(usedItemHistory.getManufactureDate());
				batchNo.setText(usedItemHistory.getBatchNumber());
			}else{
				expiration.setDate("");
				manuDate.setDate("");
				batchNo.setText("");
			}
		}

		@Override
		protected boolean save(Paddock parent, ChemicalHistory usedItemHistory) {
			ChemicalHistory ch = usedItemHistory;
			Chemical c = ((UsableItemList<Chemical>)nameCB.getSelectedItem()).getItem();
			Date d = dateField.getDate();
			double q = Double.parseDouble(quantity.getText());
			String m = (String)measurement.getSelectedItem();
			if(usedItemHistory==null){
				ch = new ChemicalHistory(c,q,m,d);
			}else{
				ch.setItem(c);
				ch.setDate(d);
				ch.setQuantity(q,m);
			}

			String co = cost.getText();
			ch.setCost(Double.parseDouble(co.equals("")?"0":co));
			
			if(manuCB.getSelectedItem()!=null&&!((String)manuCB.getSelectedItem()).trim().equals("")){
				Owner po = new Business();
				po.setName((String)manuCB.getSelectedItem());
				for(Owner o : LivestockSolutions.getOwners()){
					po = o.getName().toLowerCase().equals(((String)manuCB.getSelectedItem()).trim().toLowerCase())?o:po;
				}
				if(!(po instanceof Business)){
					po = po.changeType(Business.class);
				}
				LivestockSolutions.addOwner(po);
				ch.setOrigin((Business)po);
			}
			
			ch.setExpiryDate(expiration.getDate());
			ch.setManufactureDate(manuDate.getDate());
			ch.setBatchNumber(batchNo.getText());
			
			parent.addChemical(ch);
			dispose();
			return true;
		}
	}
}
